Skip to content

fix(variants): drop redundant thinking variant when effort enum present#42

Closed
justin-carper wants to merge 1 commit into
mainfrom
neat-raptor
Closed

fix(variants): drop redundant thinking variant when effort enum present#42
justin-carper wants to merge 1 commit into
mainfrom
neat-raptor

Conversation

@justin-carper

Copy link
Copy Markdown
Collaborator

Problem

For Anthropic/Claude models accessed via the Cursor provider, the Cursor SDK catalog exposes two reasoning params on the same model:

  • a boolean thinking = ["false","true"]
  • an effort enum, e.g. ["low","medium","high","xhigh","max"]

buildModelVariants emitted a variant for each, so opencode's variant cycler showed:

thinking + low / medium / high / xhigh / max

Standard opencode providers (driven by models.dev reasoning_options of type effort) show only the five effort levels — no thinking entry. The extra thinking variant was inconsistent and redundant (selecting any effort level already enables reasoning).

Fix

buildModelVariants (src/model-variants.ts):

  • Added a hasEffortEnum pre-pass — scans params for any non-boolean reasoning enum, order-independent.
  • Guarded the boolean reasoning branch: when hasEffortEnum is true, skip emitting the param-named boolean variant.
  • Effort variants are unchanged — no thinking:"true" baked in (effort alone enables reasoning, per design decision).

Behavior matrix

Model param shape Before After
boolean thinking + effort enum (Claude via Cursor) thinking + low/…/max low/…/max ✅ parity
boolean thinking only (no enum) thinking thinking (unchanged)
effort enum only effort levels effort levels (unchanged)
fast toggle fast opt-in + baked-off defaults unchanged

Out of scope: composer-2.5 thinking=["off","on"] (treated as enum), fast, defaultModelParams.

Tests

Updated the former dual-param test and added 4 new cases in test/model-variants.test.ts:

  1. Production claude-via-Cursor shapethinking + effort + fast: asserts thinking suppressed, fast:"false" baked into effort variants, fast opt-in present.
  2. Order-independence — effort enum declared after boolean still suppresses it.
  3. Zero-value effort enum guard — empty enum does not count; boolean thinking survives.
  4. Boolean without truethinking=["false"] + effort → only effort variants.
  5. Mixed boolean+enum param pinned["false","true","high"] current behavior pinned so a future catalog change is caught.

Verification

  • npx vitest run190 passed (18 files)
  • npx tsc --noEmit → exit 0

Review

Reviewed by code-reviewer agent: no critical issues, fix correct for all real catalog shapes. Tests added in response to its findings (production-shape+fast composition, zero-value-enum guard).

Claude models via Cursor expose both a boolean thinking param and an
effort enum. buildModelVariants emitted a variant for each, surfacing a
stray thinking entry alongside low/medium/high/xhigh/max. Standard
opencode providers (models.dev reasoning_options.effort) show only the
five effort levels, so the boolean variant broke parity.

Add a hasEffortEnum pre-pass; when true, skip the boolean reasoning
variant. Effort alone enables reasoning (no thinking:true baked in).
Boolean-only reasoning models still surface their single param-named
variant. Order-independent. fast toggle and defaultModelParams untouched.

Tests: updated dual-param expectation, added order-independence,
production-shape+fast composition, zero-value-enum guard, and pinned
current mixed-shape param behavior.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant